<!DOCTYPE HTML>
<!--
	Dimension by HTML5 UP
	html5up.net | @ajlkn
	Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
 <head>
  <title>
   Dimension by HTML5 UP
  </title>
  <!-- <meta charset="utf-8" /> -->
  <!-- <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> -->
  <meta charset="utf-8"/>
  <meta content="width=device-width,initial-scale=1.0" name="viewport"/>
  <link href="../../assets/css/article.css" rel="stylesheet"/>
  <link href="https://cdn.bootcss.com/highlight.js/9.15.8/styles/github.min.css" rel="stylesheet"/>
  <noscript>
   <link href="../../assets/css/noscript.css" rel="stylesheet"/>
  </noscript>
 </head>
 <body>
  <div id="app">
  </div>
  <!-- built files will be auto injected -->
 </body>
 <body class="is-preload">
  <!-- Wrapper -->
  <div id="wrapper">
   <!-- Main -->
   <div id="main">
    <article id="article">
     <h1 id="soul">
      Soul网关源码解析（九）插件配置加载初探
     </h1>
     <hr/>
     <h2 id="_1">
      简介
     </h2>
     <p>
      今日来探索一下插件的初始化，及相关的配置的加载
     </p>
     <h2 id="debug">
      源码Debug
     </h2>
     <h3 id="_2">
      插件初始化
     </h3>
     <p>
      首先来到我们非常熟悉的插件链调用的类： SoulWebHandler ,在其中的 DefaultSoulPluginChain ,我们看到plugins是通过构造函数传入的
     </p>
     <p>
      我们来跟踪一下是谁传入的，在SoulWebHandler的public那一行打上断点，重启后跟踪调用栈
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">SoulWebHandler</span> <span class="kd">implements</span> <span class="n">WebHandler</span> <span class="p">{</span>

    <span class="kd">private</span> <span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">SoulPlugin</span><span class="o">&gt;</span> <span class="n">plugins</span><span class="p">;</span>

    <span class="c1">// 在这里也看到plugins是通过构造函数传入的，在public这一行打上断点，然后重启</span>
    <span class="kd">public</span> <span class="nf">SoulWebHandler</span><span class="p">(</span><span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">SoulPlugin</span><span class="o">&gt;</span> <span class="n">plugins</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="na">plugins</span> <span class="o">=</span> <span class="n">plugins</span><span class="p">;</span>
        <span class="n">String</span> <span class="n">schedulerType</span> <span class="o">=</span> <span class="n">System</span><span class="p">.</span><span class="na">getProperty</span><span class="p">(</span><span class="s">"soul.scheduler.type"</span><span class="p">,</span> <span class="s">"fixed"</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">equals</span><span class="p">(</span><span class="n">schedulerType</span><span class="p">,</span> <span class="s">"fixed"</span><span class="p">))</span> <span class="p">{</span>
            <span class="kt">int</span> <span class="n">threads</span> <span class="o">=</span> <span class="n">Integer</span><span class="p">.</span><span class="na">parseInt</span><span class="p">(</span><span class="n">System</span><span class="p">.</span><span class="na">getProperty</span><span class="p">(</span>
                    <span class="s">"soul.work.threads"</span><span class="p">,</span> <span class="s">""</span> <span class="o">+</span> <span class="n">Math</span><span class="p">.</span><span class="na">max</span><span class="p">((</span><span class="n">Runtime</span><span class="p">.</span><span class="na">getRuntime</span><span class="p">().</span><span class="na">availableProcessors</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">16</span><span class="p">)));</span>
            <span class="n">scheduler</span> <span class="o">=</span> <span class="n">Schedulers</span><span class="p">.</span><span class="na">newParallel</span><span class="p">(</span><span class="s">"soul-work-threads"</span><span class="p">,</span> <span class="n">threads</span><span class="p">);</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">scheduler</span> <span class="o">=</span> <span class="n">Schedulers</span><span class="p">.</span><span class="na">elastic</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">handle</span><span class="p">(</span><span class="nd">@NonNull</span> <span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">MetricsTrackerFacade</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">counterInc</span><span class="p">(</span><span class="n">MetricsLabelEnum</span><span class="p">.</span><span class="na">REQUEST_TOTAL</span><span class="p">.</span><span class="na">getName</span><span class="p">());</span>
        <span class="n">Optional</span><span class="o">&lt;</span><span class="n">HistogramMetricsTrackerDelegate</span><span class="o">&gt;</span> <span class="n">startTimer</span> <span class="o">=</span> <span class="n">MetricsTrackerFacade</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">histogramStartTimer</span><span class="p">(</span><span class="n">MetricsLabelEnum</span><span class="p">.</span><span class="na">REQUEST_LATENCY</span><span class="p">.</span><span class="na">getName</span><span class="p">());</span>
        <span class="c1">// 传入 plugins 到 DefaultSoulPluginChain</span>
        <span class="k">return</span> <span class="k">new</span> <span class="n">DefaultSoulPluginChain</span><span class="p">(</span><span class="n">plugins</span><span class="p">).</span><span class="na">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">).</span><span class="na">subscribeOn</span><span class="p">(</span><span class="n">scheduler</span><span class="p">)</span>
                <span class="p">.</span><span class="na">doOnSuccess</span><span class="p">(</span><span class="n">t</span> <span class="o">-&gt;</span> <span class="n">startTimer</span><span class="p">.</span><span class="na">ifPresent</span><span class="p">(</span><span class="n">time</span> <span class="o">-&gt;</span> <span class="n">MetricsTrackerFacade</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">histogramObserveDuration</span><span class="p">(</span><span class="n">time</span><span class="p">)));</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">DefaultSoulPluginChain</span> <span class="kd">implements</span> <span class="n">SoulPluginChain</span> <span class="p">{</span>

        <span class="kd">private</span> <span class="kt">int</span> <span class="n">index</span><span class="p">;</span>

        <span class="kd">private</span> <span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">SoulPlugin</span><span class="o">&gt;</span> <span class="n">plugins</span><span class="p">;</span>

        <span class="c1">// 通过构造函数得到 plugins</span>
        <span class="n">DefaultSoulPluginChain</span><span class="p">(</span><span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">SoulPlugin</span><span class="o">&gt;</span> <span class="n">plugins</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">this</span><span class="p">.</span><span class="na">plugins</span> <span class="o">=</span> <span class="n">plugins</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="nd">@Override</span>
        <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">execute</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">Mono</span><span class="p">.</span><span class="na">defer</span><span class="p">(()</span> <span class="o">-&gt;</span> <span class="p">{</span>
                <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">index</span> <span class="o">&lt;</span> <span class="n">plugins</span><span class="p">.</span><span class="na">size</span><span class="p">())</span> <span class="p">{</span>
                    <span class="n">SoulPlugin</span> <span class="n">plugin</span> <span class="o">=</span> <span class="n">plugins</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">index</span><span class="o">++</span><span class="p">);</span>
                    <span class="n">Boolean</span> <span class="n">skip</span> <span class="o">=</span> <span class="n">plugin</span><span class="p">.</span><span class="na">skip</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">skip</span><span class="p">)</span> <span class="p">{</span>
                        <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="na">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
                    <span class="p">}</span>
                    <span class="k">return</span> <span class="n">plugin</span><span class="p">.</span><span class="na">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="k">this</span><span class="p">);</span>
                <span class="p">}</span>
                <span class="k">return</span> <span class="n">Mono</span><span class="p">.</span><span class="na">empty</span><span class="p">();</span>
            <span class="p">});</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      我这有点慢，重启等以后后，我们查看上一个调用，来到了 SoulConfiguration
     </p>
     <p>
      通过类的大致信息可以看到是Spring之类的加载机制。通过前面文章的分析中，大致应该就是配置了 auto configuration ，然后启动的时候Spring进行加载的
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">SoulConfiguration</span> <span class="p">{</span>

    <span class="nd">@Bean</span><span class="p">(</span><span class="s">"webHandler"</span><span class="p">)</span>
    <span class="kd">public</span> <span class="n">SoulWebHandler</span> <span class="nf">soulWebHandler</span><span class="p">(</span><span class="kd">final</span> <span class="n">ObjectProvider</span><span class="o">&lt;</span><span class="n">List</span><span class="o">&lt;</span><span class="n">SoulPlugin</span><span class="o">&gt;&gt;</span> <span class="n">plugins</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">List</span><span class="o">&lt;</span><span class="n">SoulPlugin</span><span class="o">&gt;</span> <span class="n">pluginList</span> <span class="o">=</span> <span class="n">plugins</span><span class="p">.</span><span class="na">getIfAvailable</span><span class="p">(</span><span class="n">Collections</span><span class="p">::</span><span class="n">emptyList</span><span class="p">);</span>
        <span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">SoulPlugin</span><span class="o">&gt;</span> <span class="n">soulPlugins</span> <span class="o">=</span> <span class="n">pluginList</span><span class="p">.</span><span class="na">stream</span><span class="p">()</span>
                <span class="p">.</span><span class="na">sorted</span><span class="p">(</span><span class="n">Comparator</span><span class="p">.</span><span class="na">comparingInt</span><span class="p">(</span><span class="n">SoulPlugin</span><span class="p">::</span><span class="n">getOrder</span><span class="p">)).</span><span class="na">collect</span><span class="p">(</span><span class="n">Collectors</span><span class="p">.</span><span class="na">toList</span><span class="p">());</span>
        <span class="n">soulPlugins</span><span class="p">.</span><span class="na">forEach</span><span class="p">(</span><span class="n">soulPlugin</span> <span class="o">-&gt;</span> <span class="n">log</span><span class="p">.</span><span class="na">info</span><span class="p">(</span><span class="s">"load plugin:[{}] [{}]"</span><span class="p">,</span> <span class="n">soulPlugin</span><span class="p">.</span><span class="na">named</span><span class="p">(),</span> <span class="n">soulPlugin</span><span class="p">.</span><span class="na">getClass</span><span class="p">().</span><span class="na">getName</span><span class="p">()));</span>
        <span class="k">return</span> <span class="k">new</span> <span class="n">SoulWebHandler</span><span class="p">(</span><span class="n">soulPlugins</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      大致就知道是Spring自动加载的，通过AutoConfiguration机制，下面就是Spring相关了，这里就不继续跟踪了
     </p>
     <h3 id="_3">
      配置初始化
     </h3>
     <p>
      在上一篇的文章分析中，我们分析了路由匹配的大致细节，需要选择器和规则的配置，下面我们来跟踪一下这些配置的初始化
     </p>
     <p>
      首先进入路由匹配核心类： AbstractSoulPlugin ，其中进行 pluginData 、selectorData、rules的获取，如下面代码注释：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">AbstractSoulPlugin</span> <span class="kd">implements</span> <span class="n">SoulPlugin</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">execute</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">,</span> <span class="kd">final</span> <span class="n">SoulPluginChain</span> <span class="n">chain</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">pluginName</span> <span class="o">=</span> <span class="n">named</span><span class="p">();</span>
        <span class="c1">// 获取插件数据</span>
        <span class="kd">final</span> <span class="n">PluginData</span> <span class="n">pluginData</span> <span class="o">=</span> <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">obtainPluginData</span><span class="p">(</span><span class="n">pluginName</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">pluginData</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">pluginData</span><span class="p">.</span><span class="na">getEnabled</span><span class="p">())</span> <span class="p">{</span>
            <span class="c1">// 根据插件名称，获取选择器数据</span>
            <span class="kd">final</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">SelectorData</span><span class="o">&gt;</span> <span class="n">selectors</span> <span class="o">=</span> <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">obtainSelectorData</span><span class="p">(</span><span class="n">pluginName</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">(</span><span class="n">selectors</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span> <span class="n">handleSelectorIsNull</span><span class="p">(</span><span class="n">pluginName</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="kd">final</span> <span class="n">SelectorData</span> <span class="n">selectorData</span> <span class="o">=</span> <span class="n">matchSelector</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">selectors</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">isNull</span><span class="p">(</span><span class="n">selectorData</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span> <span class="n">handleSelectorIsNull</span><span class="p">(</span><span class="n">pluginName</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="n">selectorLog</span><span class="p">(</span><span class="n">selectorData</span><span class="p">,</span> <span class="n">pluginName</span><span class="p">);</span>
            <span class="c1">// 根据选择器的id，获取其规则数据</span>
            <span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">RuleData</span><span class="o">&gt;</span> <span class="n">rules</span> <span class="o">=</span> <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">obtainRuleData</span><span class="p">(</span><span class="n">selectorData</span><span class="p">.</span><span class="na">getId</span><span class="p">());</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">(</span><span class="n">rules</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span> <span class="n">handleRuleIsNull</span><span class="p">(</span><span class="n">pluginName</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="n">RuleData</span> <span class="n">rule</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">selectorData</span><span class="p">.</span><span class="na">getType</span><span class="p">()</span> <span class="o">==</span> <span class="n">SelectorTypeEnum</span><span class="p">.</span><span class="na">FULL_FLOW</span><span class="p">.</span><span class="na">getCode</span><span class="p">())</span> <span class="p">{</span>
                <span class="n">rule</span> <span class="o">=</span> <span class="n">rules</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">rules</span><span class="p">.</span><span class="na">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">rule</span> <span class="o">=</span> <span class="n">matchRule</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">rules</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">isNull</span><span class="p">(</span><span class="n">rule</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span> <span class="n">handleRuleIsNull</span><span class="p">(</span><span class="n">pluginName</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="n">ruleLog</span><span class="p">(</span><span class="n">rule</span><span class="p">,</span> <span class="n">pluginName</span><span class="p">);</span>
            <span class="k">return</span> <span class="n">doExecute</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">,</span> <span class="n">selectorData</span><span class="p">,</span> <span class="n">rule</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">chain</span><span class="p">.</span><span class="na">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      我们到这个类： BaseDataCache 看一下，看到它有两个数据的Map存储：插件数据、选择器数据、规则数据
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">BaseDataCache</span> <span class="p">{</span>

    <span class="cm">/**</span>
<span class="cm">     * pluginName -&gt; PluginData.</span>
<span class="cm">     */</span>
    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">ConcurrentMap</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span> <span class="n">PluginData</span><span class="o">&gt;</span> <span class="n">PLUGIN_MAP</span> <span class="o">=</span> <span class="n">Maps</span><span class="p">.</span><span class="na">newConcurrentMap</span><span class="p">();</span>

    <span class="cm">/**</span>
<span class="cm">     * pluginName -&gt; SelectorData.</span>
<span class="cm">     */</span>
    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">ConcurrentMap</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">SelectorData</span><span class="o">&gt;&gt;</span> <span class="n">SELECTOR_MAP</span> <span class="o">=</span> <span class="n">Maps</span><span class="p">.</span><span class="na">newConcurrentMap</span><span class="p">();</span>

    <span class="cm">/**</span>
<span class="cm">     * selectorId -&gt; RuleData.</span>
<span class="cm">     */</span>
    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">ConcurrentMap</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">RuleData</span><span class="o">&gt;&gt;</span> <span class="n">RULE_MAP</span> <span class="o">=</span> <span class="n">Maps</span><span class="p">.</span><span class="na">newConcurrentMap</span><span class="p">();</span>

<span class="p">}</span>
</code></pre>
     </div>
     <p>
      我们发现它是一个静态单例，而插件数据的配置是使用下面的函数，我们在函数上打上断点，看看是谁调用了它，它的调用栈是怎么样的
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">BaseDataCache</span> <span class="p">{</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">cachePluginData</span><span class="p">(</span><span class="kd">final</span> <span class="n">PluginData</span> <span class="n">pluginData</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">Optional</span><span class="p">.</span><span class="na">ofNullable</span><span class="p">(</span><span class="n">pluginData</span><span class="p">).</span><span class="na">ifPresent</span><span class="p">(</span><span class="n">data</span> <span class="o">-&gt;</span> <span class="n">PLUGIN_MAP</span><span class="p">.</span><span class="na">put</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="na">getName</span><span class="p">(),</span> <span class="n">data</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      在public这一行打上断点，重启，顺利进入上面的函数，我们查看下 pluginData ，还挺简单，大致如下
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="err">PluginData(id=1, name=sign, config=null, role=1, enabled=false)</span>
</code></pre>
     </div>
     <p>
      我们跟踪其调用栈，其调用链的类和函数如下，类在调用栈的顺序也是对应的
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">CommonPluginDataSubscriber</span> <span class="kd">implements</span> <span class="n">PluginDataSubscriber</span> <span class="p">{</span>

    <span class="c1">// 在这个里面触发 subscribeDataHandler , subscribeDataHandler 触发 DaseDataCache的调用</span>
    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onSubscribe</span><span class="p">(</span><span class="kd">final</span> <span class="n">PluginData</span> <span class="n">pluginData</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">subscribeDataHandler</span><span class="p">(</span><span class="n">pluginData</span><span class="p">,</span> <span class="n">DataEventTypeEnum</span><span class="p">.</span><span class="na">UPDATE</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="nf">subscribeDataHandler</span><span class="p">(</span><span class="kd">final</span> <span class="n">T</span> <span class="n">classData</span><span class="p">,</span> <span class="kd">final</span> <span class="n">DataEventTypeEnum</span> <span class="n">dataType</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">Optional</span><span class="p">.</span><span class="na">ofNullable</span><span class="p">(</span><span class="n">classData</span><span class="p">).</span><span class="na">ifPresent</span><span class="p">(</span><span class="n">data</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="c1">// 插件数据的操作</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">data</span> <span class="k">instanceof</span> <span class="n">PluginData</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">PluginData</span> <span class="n">pluginData</span> <span class="o">=</span> <span class="p">(</span><span class="n">PluginData</span><span class="p">)</span> <span class="n">data</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">dataType</span> <span class="o">==</span> <span class="n">DataEventTypeEnum</span><span class="p">.</span><span class="na">UPDATE</span><span class="p">)</span> <span class="p">{</span>
                    <span class="c1">// 在这进行触发调用</span>
                    <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">cachePluginData</span><span class="p">(</span><span class="n">pluginData</span><span class="p">);</span>
                    <span class="n">Optional</span><span class="p">.</span><span class="na">ofNullable</span><span class="p">(</span><span class="n">handlerMap</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">pluginData</span><span class="p">.</span><span class="na">getName</span><span class="p">())).</span><span class="na">ifPresent</span><span class="p">(</span><span class="n">handler</span> <span class="o">-&gt;</span> <span class="n">handler</span><span class="p">.</span><span class="na">handlerPlugin</span><span class="p">(</span><span class="n">pluginData</span><span class="p">));</span>
                <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">dataType</span> <span class="o">==</span> <span class="n">DataEventTypeEnum</span><span class="p">.</span><span class="na">DELETE</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">removePluginData</span><span class="p">(</span><span class="n">pluginData</span><span class="p">);</span>
                    <span class="n">Optional</span><span class="p">.</span><span class="na">ofNullable</span><span class="p">(</span><span class="n">handlerMap</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">pluginData</span><span class="p">.</span><span class="na">getName</span><span class="p">())).</span><span class="na">ifPresent</span><span class="p">(</span><span class="n">handler</span> <span class="o">-&gt;</span> <span class="n">handler</span><span class="p">.</span><span class="na">removePlugin</span><span class="p">(</span><span class="n">pluginData</span><span class="p">));</span>
                <span class="p">}</span>
            <span class="c1">// 选择器的操作</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">data</span> <span class="k">instanceof</span> <span class="n">SelectorData</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">SelectorData</span> <span class="n">selectorData</span> <span class="o">=</span> <span class="p">(</span><span class="n">SelectorData</span><span class="p">)</span> <span class="n">data</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">dataType</span> <span class="o">==</span> <span class="n">DataEventTypeEnum</span><span class="p">.</span><span class="na">UPDATE</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">cacheSelectData</span><span class="p">(</span><span class="n">selectorData</span><span class="p">);</span>
                    <span class="n">Optional</span><span class="p">.</span><span class="na">ofNullable</span><span class="p">(</span><span class="n">handlerMap</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">selectorData</span><span class="p">.</span><span class="na">getPluginName</span><span class="p">())).</span><span class="na">ifPresent</span><span class="p">(</span><span class="n">handler</span> <span class="o">-&gt;</span> <span class="n">handler</span><span class="p">.</span><span class="na">handlerSelector</span><span class="p">(</span><span class="n">selectorData</span><span class="p">));</span>
                <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">dataType</span> <span class="o">==</span> <span class="n">DataEventTypeEnum</span><span class="p">.</span><span class="na">DELETE</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">removeSelectData</span><span class="p">(</span><span class="n">selectorData</span><span class="p">);</span>
                    <span class="n">Optional</span><span class="p">.</span><span class="na">ofNullable</span><span class="p">(</span><span class="n">handlerMap</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">selectorData</span><span class="p">.</span><span class="na">getPluginName</span><span class="p">())).</span><span class="na">ifPresent</span><span class="p">(</span><span class="n">handler</span> <span class="o">-&gt;</span> <span class="n">handler</span><span class="p">.</span><span class="na">removeSelector</span><span class="p">(</span><span class="n">selectorData</span><span class="p">));</span>
                <span class="p">}</span>
            <span class="c1">// 规则的操作</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">data</span> <span class="k">instanceof</span> <span class="n">RuleData</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">RuleData</span> <span class="n">ruleData</span> <span class="o">=</span> <span class="p">(</span><span class="n">RuleData</span><span class="p">)</span> <span class="n">data</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">dataType</span> <span class="o">==</span> <span class="n">DataEventTypeEnum</span><span class="p">.</span><span class="na">UPDATE</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">cacheRuleData</span><span class="p">(</span><span class="n">ruleData</span><span class="p">);</span>
                    <span class="n">Optional</span><span class="p">.</span><span class="na">ofNullable</span><span class="p">(</span><span class="n">handlerMap</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">ruleData</span><span class="p">.</span><span class="na">getPluginName</span><span class="p">())).</span><span class="na">ifPresent</span><span class="p">(</span><span class="n">handler</span> <span class="o">-&gt;</span> <span class="n">handler</span><span class="p">.</span><span class="na">handlerRule</span><span class="p">(</span><span class="n">ruleData</span><span class="p">));</span>
                <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">dataType</span> <span class="o">==</span> <span class="n">DataEventTypeEnum</span><span class="p">.</span><span class="na">DELETE</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">removeRuleData</span><span class="p">(</span><span class="n">ruleData</span><span class="p">);</span>
                    <span class="n">Optional</span><span class="p">.</span><span class="na">ofNullable</span><span class="p">(</span><span class="n">handlerMap</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">ruleData</span><span class="p">.</span><span class="na">getPluginName</span><span class="p">())).</span><span class="na">ifPresent</span><span class="p">(</span><span class="n">handler</span> <span class="o">-&gt;</span> <span class="n">handler</span><span class="p">.</span><span class="na">removeRule</span><span class="p">(</span><span class="n">ruleData</span><span class="p">));</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// 这个类中触发了上面单个插件的配置，并且这个类拿到了所有的插件数据</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">PluginDataHandler</span> <span class="kd">extends</span> <span class="n">AbstractDataHandler</span><span class="o">&lt;</span><span class="n">PluginData</span><span class="o">&gt;</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">doRefresh</span><span class="p">(</span><span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">PluginData</span><span class="o">&gt;</span> <span class="n">dataList</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// 触发上面的调用</span>
        <span class="n">pluginDataSubscriber</span><span class="p">.</span><span class="na">refreshPluginDataSelf</span><span class="p">(</span><span class="n">dataList</span><span class="p">);</span>
        <span class="n">dataList</span><span class="p">.</span><span class="na">forEach</span><span class="p">(</span><span class="n">pluginDataSubscriber</span><span class="p">::</span><span class="n">onSubscribe</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// 继续跟下去，看看datalist的来源</span>
<span class="kd">public</span> <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">AbstractDataHandler</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="kd">implements</span> <span class="n">DataHandler</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">handle</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">json</span><span class="p">,</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">eventType</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">List</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">dataList</span> <span class="o">=</span> <span class="n">convert</span><span class="p">(</span><span class="n">json</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isNotEmpty</span><span class="p">(</span><span class="n">dataList</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">DataEventTypeEnum</span> <span class="n">eventTypeEnum</span> <span class="o">=</span> <span class="n">DataEventTypeEnum</span><span class="p">.</span><span class="na">acquireByName</span><span class="p">(</span><span class="n">eventType</span><span class="p">);</span>
            <span class="k">switch</span> <span class="p">(</span><span class="n">eventTypeEnum</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">case</span> <span class="n">REFRESH</span><span class="p">:</span>
                <span class="k">case</span> <span class="n">MYSELF</span><span class="p">:</span>
                    <span class="c1">// 触发上面函数的调用</span>
                    <span class="n">doRefresh</span><span class="p">(</span><span class="n">dataList</span><span class="p">);</span>
                    <span class="k">break</span><span class="p">;</span>
                <span class="k">case</span> <span class="n">UPDATE</span><span class="p">:</span>
                <span class="k">case</span> <span class="n">CREATE</span><span class="p">:</span>
                    <span class="n">doUpdate</span><span class="p">(</span><span class="n">dataList</span><span class="p">);</span>
                    <span class="k">break</span><span class="p">;</span>
                <span class="k">case</span> <span class="n">DELETE</span><span class="p">:</span>
                    <span class="n">doDelete</span><span class="p">(</span><span class="n">dataList</span><span class="p">);</span>
                    <span class="k">break</span><span class="p">;</span>
                <span class="k">default</span><span class="p">:</span>
                    <span class="k">break</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// 来到了websocket，进行跟</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">WebsocketDataHandler</span> <span class="p">{</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">executor</span><span class="p">(</span><span class="kd">final</span> <span class="n">ConfigGroupEnum</span> <span class="n">type</span><span class="p">,</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">json</span><span class="p">,</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">eventType</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">ENUM_MAP</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">type</span><span class="p">).</span><span class="na">handle</span><span class="p">(</span><span class="n">json</span><span class="p">,</span> <span class="n">eventType</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// 在这个类中，看到插件数据列表是从websocket来的，那就是从Soul-Admin那边获取来到的数据</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">SoulWebsocketClient</span> <span class="kd">extends</span> <span class="n">WebSocketClient</span> <span class="p">{</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMessage</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">result</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">handleResult</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>
    <span class="p">}</span>  

    <span class="nd">@SuppressWarnings</span><span class="p">(</span><span class="s">"ALL"</span><span class="p">)</span>
    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">handleResult</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">result</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">WebsocketData</span> <span class="n">websocketData</span> <span class="o">=</span> <span class="n">GsonUtils</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">fromJson</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">WebsocketData</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
        <span class="n">ConfigGroupEnum</span> <span class="n">groupEnum</span> <span class="o">=</span> <span class="n">ConfigGroupEnum</span><span class="p">.</span><span class="na">acquireByName</span><span class="p">(</span><span class="n">websocketData</span><span class="p">.</span><span class="na">getGroupType</span><span class="p">());</span>
        <span class="n">String</span> <span class="n">eventType</span> <span class="o">=</span> <span class="n">websocketData</span><span class="p">.</span><span class="na">getEventType</span><span class="p">();</span>
        <span class="n">String</span> <span class="n">json</span> <span class="o">=</span> <span class="n">GsonUtils</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">toJson</span><span class="p">(</span><span class="n">websocketData</span><span class="p">.</span><span class="na">getData</span><span class="p">());</span>
        <span class="n">websocketDataHandler</span><span class="p">.</span><span class="na">executor</span><span class="p">(</span><span class="n">groupEnum</span><span class="p">,</span> <span class="n">json</span><span class="p">,</span> <span class="n">eventType</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      看下result的大致内容：也就是一些简单的配置
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="p">{</span>
    <span class="nt">"groupType"</span><span class="p">:</span> <span class="s2">"PLUGIN"</span><span class="p">,</span>
    <span class="nt">"eventType"</span><span class="p">:</span> <span class="s2">"MYSELF"</span><span class="p">,</span>
    <span class="nt">"data"</span><span class="p">:</span> <span class="p">[{</span>
        <span class="nt">"id"</span><span class="p">:</span> <span class="s2">"1"</span><span class="p">,</span>
        <span class="nt">"name"</span><span class="p">:</span> <span class="s2">"sign"</span><span class="p">,</span>
        <span class="nt">"role"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
        <span class="nt">"enabled"</span><span class="p">:</span> <span class="kc">false</span>
    <span class="p">},</span> <span class="p">{</span>
        <span class="nt">"id"</span><span class="p">:</span> <span class="s2">"9"</span><span class="p">,</span>
        <span class="nt">"name"</span><span class="p">:</span> <span class="s2">"hystrix"</span><span class="p">,</span>
        <span class="nt">"role"</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
        <span class="nt">"enabled"</span><span class="p">:</span> <span class="kc">false</span>
    <span class="p">}]</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      结合路由匹配的关键函数,好像它的作用就是用来判断是否开启和根据name获得选择器
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">AbstractSoulPlugin</span> <span class="kd">implements</span> <span class="n">SoulPlugin</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">execute</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">,</span> <span class="kd">final</span> <span class="n">SoulPluginChain</span> <span class="n">chain</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">pluginName</span> <span class="o">=</span> <span class="n">named</span><span class="p">();</span>
        <span class="kd">final</span> <span class="n">PluginData</span> <span class="n">pluginData</span> <span class="o">=</span> <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">obtainPluginData</span><span class="p">(</span><span class="n">pluginName</span><span class="p">);</span>
        <span class="c1">// 用于判断是否开启</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">pluginData</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">pluginData</span><span class="p">.</span><span class="na">getEnabled</span><span class="p">())</span> <span class="p">{</span>
            <span class="p">.......</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      插件数据这一块的流程定位下来比较轻松，毕竟前面流程也梳理差不多了
     </p>
     <p>
      选择器和规则数据的初始化流程，这里就不进行定位了，逻辑和插件数据基本一样，这里就不赘述了
     </p>
     <h2 id="_4">
      总结
     </h2>
     <p>
      今天分析了插件的初始化和相关配置的初始化
     </p>
     <p>
      插件的初始化是使用Spring的自动配置加载机制进行实现了，结合使用插件都需要引入哪些start的依赖
     </p>
     <p>
      插件数据、选择器数据、规则数据的初始化，都是从Websocket（或者同步通信模块）那边过来的，接收到数据以后，进行配置加载到本地
     </p>
     <p>
      我们还看到一些删除和更新相关的操作，这些属于后面的数据同步分析了，这里先放一放
     </p>
     <h2 id="soul_1">
      Soul网关源码分析文章列表
     </h2>
     <h3 id="github">
      Github
     </h3>
     <ul>
      <li>
       <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB1-%E6%A6%82%E8%A7%88.md">
        Soul源码阅读（一） 概览
       </a>
      </li>
      <li>
       <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB2-%E5%88%9D%E6%AD%A5%E8%BF%90%E8%A1%8C.md">
        Soul源码阅读（二）代码初步运行
       </a>
      </li>
      <li>
       <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB3-%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md">
        Soul源码阅读（三）HTTP请求处理概览
       </a>
      </li>
      <li>
       <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB4-dubbo%E8%AF%B7%E6%B1%82%E6%A6%82%E8%A7%88.md">
        Soul网关源码阅读（四）Dubbo请求概览
       </a>
      </li>
      <li>
       <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB5-%E8%AF%B7%E6%B1%82%E7%B1%BB%E5%9E%8B%E6%8E%A2%E7%B4%A2.md">
        Soul网关源码阅读（五）请求类型探索
       </a>
      </li>
      <li>
       <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md">
        Soul网关源码阅读（六）Sofa请求处理概览
       </a>
      </li>
      <li>
       <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB7-%E9%99%90%E6%B5%81%E6%8F%92%E4%BB%B6%E5%88%9D%E6%8E%A2.md">
        Soul网关源码阅读（七）限流插件初探
       </a>
      </li>
      <li>
       <p>
        <a href="https://github.com/lw1243925457/SE-Notes/blob/0e6931519a84d5c603504b2c6a633698ac793b70/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB8-%E8%B7%AF%E7%94%B1%E5%8C%B9%E9%85%8D%E5%88%9D%E6%8E%A2.md">
         Soul网关源码阅读（八）路由匹配初探
        </a>
       </p>
      </li>
      <li>
       <p>
        <a href="https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB%E7%95%AA%E5%A4%96%E7%AF%871-HTTP%E7%A4%BA%E4%BE%8B%E5%8F%82%E6%95%B0%E8%AF%B7%E6%B1%82%E9%94%99%E8%AF%AF.md">
         Soul网关源码阅读番外篇（一） HTTP参数请求错误
        </a>
       </p>
      </li>
     </ul>
     <h3 id="_5">
      掘金
     </h3>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6917864624423436296">
        Soul网关源码阅读（一） 概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917865804121767944">
        Soul网关源码阅读（二）代码初步运行
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917866538712334343">
        Soul网关源码阅读（三）请求处理概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917867369909977102">
        Soul网关源码阅读（四）Dubbo请求概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918575905962983438">
        Soul网关源码阅读（五）请求类型探索
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918736260467015693">
        Soul网关源码阅读（六）Sofa请求处理概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6919348164944232455/">
        Soul网关源码阅读（七）限流插件初探
       </a>
      </li>
      <li>
       <p>
        <a href="https://juejin.cn/post/6919774553241550855/">
         Soul网关源码阅读（八）路由匹配初探
        </a>
       </p>
      </li>
      <li>
       <p>
        <a href="https://juejin.cn/post/6918947689564471309">
         Soul网关源码阅读番外篇（一） HTTP参数请求错误
        </a>
       </p>
      </li>
     </ul>
    </article>
   </div>
   <!-- Footer -->
   <footer id="footer">
    <p class="copyright">
     © Untitled. Design:
     <a href="https://html5up.net">
      HTML5 UP
     </a>
     .
    </p>
   </footer>
  </div>
  <!-- BG -->
  <div id="bg">
  </div>
  <!-- Scripts -->
  <script src="../assets/js/jquery.min.js">
  </script>
  <script src="../assets/js/browser.min.js">
  </script>
  <script src="../assets/js/breakpoints.min.js">
  </script>
  <script src="../assets/js/util.js">
  </script>
  <script src="../assets/js/main.js">
  </script>
 </body>
</html>
